{-------------------------- SIPS Module -------------------------

Title: SIPS Customized Common Routines, SLS Version
File: SIPSXM-SLS

Author: R.D.Villwock aka 'Big Bob'

First Written: September 18, 2006

Current Version: 1.51

Last Modified: June 5, 2007

-----------------------------------------------------------------}
{ ---------------- Data Constructor Functions ---------------- }
function on_init_Bend
  family Bend { Bend parameter family with add-on BtnMenu }

  { Bend amount Edit-Box and related add-on MIDI controls/parameters }  

    declare ui_value_edit Knob (0,MaxBend,1)  { Bend amount in cents }

    declare ui_value_edit Range (MinRng,MaxRng,1) { MIDI CC add-on range }

    declare iKnob       { Image of last Bend Edit-Box setting }

    declare Kmax := MaxBend    { Max allowed Bend value }
    declare ui_button Btn      { CC Menu launch button }

    declare CC     { CC#, 0 = unassigned, 128 = PW }
    declare x      { Current panel location of Bend.Btn }

    declare y

    declare state  { Current state of button (on/off) }

    declare @cap   { Prefix of button caption }     
  end family { Bend } 
  set_text(Bend.Knob,'Bend (cts)')  { Name the Bend Edit and }

  Bend.cap := 'Bend CC'             { Menu-Button caption prefix}  
  set_text(Bend.Range,'CC Range')   { Name add-on Range Edit control }

       { Legacy Panel Control Names for Bend stuff }

  declare $Bend    { Legacy Name for Bend.Knob prior to V150 }

  declare IBend    { Legacy Name for Bend.iKnob prior to V150 }

  declare BendRng  { Legacy Name for Bend.Range prior to V150 }

  declare Bend_CC  { Legacy Name for Bend.CC prior to V150 }

  if Global[G_PFC] < V150  { Updating from version prior to V150 }

    _read_persistent_var($Bend)   { Recall prior panel settings }

    _read_persistent_var(IBend)

    _read_persistent_var(BendRng)

    _read_persistent_var(Bend_CC)
    if Bend_CC = -1
      Bend_CC := PitchWheel
    end if

    Bend.Knob := $Bend     { Initialize to prior version parms }

    Bend.iKnob := IBend

    Bend.Range := BendRng

    Bend.CC := Bend_CC

  else  { Set 'fresh' install defaults for Panel Parms }

    Bend.Knob := MainParms[uBend] { Default it to Inst_0 }

    Bend.iKnob := Bend.Knob       { Default Image to same as Knob }

    Bend.Range := DefRng          { Standard initial range }

    Bend.CC := 0                  { Default to CC unassigned }     

  end if    

  _read_persistent_var(Bend.CC)   { Restore prior CC assignment }

  SetBtn(Bend)   
end function { on_init_Bend }

function on_init_BTime
  family BTime { BTime parameter family with add-on BtnMenu }

    declare ui_knob Knob (0,MaxBTime,1)  { BTime amount in ms, 0 = Off }

    declare ui_value_edit Range (MinRng,MaxRng,1) { MIDI CC add-on range }

    declare iKnob       { Image of last BTime Knob setting }

    declare Kmax := MaxBTime    { Max allowed BTime value }
    declare ui_button Btn       { CC Menu launch button }
    declare CC     { CC#, 0 = unassigned, 128 = PW }    
    declare x      { Current panel location of BTime.Btn }
    declare y
    declare state  { Current state of button (on/off) }
    declare @cap   { Prefix of button caption } 

  end family { BTime }
  set_text(BTime.Knob,' BTime')          { Name the BTime Knob and }

  set_knob_unit(BTime.Knob,KNOB_UNIT_MS) { Set unit display to ms  }
  BTime.cap := 'BTime CC'           { Menu-Button caption prefix }
  set_text(BTime.Range,'CC Range')  { Name add-on Range Edit control }

       { Legacy Panel Control Names for BTime stuff }

  declare $BTime   { Legacy Name for BTime.Knob prior to V150 }

  declare IBTime   { Legacy Name for BTime.iKnob prior to V150 }
  declare BTmRng   { Legacy Name for BTime.Range prior to V150 }

  declare BTm_CC   { Legacy Name for BTime.CC prior to V150 }

  if Global[G_PFC] < V150  { Updating from version prior to V150 }

    _read_persistent_var($BTime)   { Recall prior panel settings }

    _read_persistent_var(IBTime)

    _read_persistent_var(BTmRng)
    _read_persistent_var(BTm_CC)
    if BTm_CC = -1
      BTm_CC := PitchWheel
    end if

    BTime.Knob := $BTime     { Initialize to prior version parms }

    BTime.iKnob := IBTime
    BTime.Range := BTmRng

    BTime.CC := BTm_CC

  else  { Set 'fresh' install defaults for Panel Parms }

    BTime.Knob := MainParms[uBTime] { Default it to Inst_0 }

    BTime.iKnob := BTime.Knob       { Default Image to same as Knob }

    BTime.Range := DefRng           { Standard initial range }

    BTime.CC := 0                   { Default to CC unassigned }     

  end if  

  _read_persistent_var(BTime.CC)    { Restore prior CC assignment }

  SetBtn(BTime)   
end function { on_init_BTime }

function on_init_LegCC

  family Leg { Mode CC parameter family with std BtnMenu }}  

    declare ui_button Btn   { CC Menu launch button }
    declare CC          { CC#, 0 = unassigned, 128 = PW }    

    declare x     { Current panel location of Leg.Btn }

    declare y

    declare state  { Current state of button (on/off) }

    declare @cap   { Prefix of button caption }

  end family { BTime }
  Leg.cap := 'Mode CC'  { Menu-button caption prefix }

  declare LegCC    { Legacy Name for Leg.CC prior to V150 }
  if Global[G_PFC] < V150  { Updating from version prior to V150 }

    _read_persistent_var(LegCC)     { Recall prior panel setting }

    Leg.CC := LegCC             { Use Prior LegCC when updating }
  else  { Initialize Leg.CC for 'fresh' install default }
    Leg.CC := 0                 { Default to unassigned }

  end if 
  _read_persistent_var(Leg.CC)  { If updating from self (V150) }
  SetBtn(Leg)         { Disp;ay prior or default CC assignment }    

end function { on_init_LegCC }

function on_init_Set_UIX
{ These constants are used for two main purposes. As 'Offsets' and 
  'handles. The 'Offsets' are used to access Preset parameters and
  the 'handles' are used in Panel Maps to specify what controls to
  display in the corresponding positions. Most Preset parms are also
  panel controls but not all panel controls are included in the Presets.
  Also, a few Preset parms are not actually controls. Actual controls
  are prefixed by a lower-case 'u' or 't'. Preset parm offsets that do
  not refer to a control are prefixed by a lower-case 'p'. For Panel
  Maps, the SetXY routine need not refer to this latter type and
  therefore these index values can be re-used by controls that aren't
  included in the Preset parms. }
  declare const uXTime    := 0  { Offsets for Key Parameters }

  declare const uAtkFade  := 1

  declare const uNodeVol  := 2  

  declare const uBTime    := 3

  declare const uSlope    := 4

  declare const uBend     := 5

  declare const uRlsFade  := 6

  declare const uRlsMode  := 7

  declare const uOffset   := 8

  declare const uOfstMode := 9

  declare const uXTmRng   := 10  { Offsets for extended parms }

  declare const uXTmCC    := 11

  declare const uBTmRng   := 12

  declare const uBTmCC    := 13

  declare const uBndRng   := 14

  declare const uBndCC    := 15

  declare const pLowKey   := 16  { Parm only, not a UI Control }

  declare const pTopKey   := 17  { Parm only, not a UI Control }

  declare const uSLSMode  := 18

  declare const uLegCC    := 19

  declare const UP_Empty := uAtkFade { User preset empty when zero }
  declare const uPreset   := 16  { Remaining panel controls }
  declare const uSetIR    := 17
  declare const uAlpha    := 20
  declare const uBackSp   := 21
  declare const uEntChr   := 22
  declare const uLoCase   := 23
  declare const uErase    := 24
  declare const tNameDsp  := 25  { Panel Labels (tags) }
  declare const tImpErr   := 26
  declare const tXFCap1   := 27
  declare const tXFCap2   := 28
  declare const tBTmCap   := 29
  declare const tBndCap1  := 30
  declare const tBndCap2  := 31
  declare const tIRBox    := 32  
  declare const tModeCap  := 33
  declare const MaxControl := tModeCap { Highest Control Index }
  declare const xxx       := -1  { Unused anchor position }
end function { on_init_Set_UIX }


function on_init_SLSMode

  declare ui_menu SLSMode   { Legato/Solo/Disable SLS mode menu }

    add_menu_item (SLSMode,' Legato Mode',Legato_Mode)

    add_menu_item (SLSMode,'  Solo Mode',Solo_Mode)

    add_menu_item (SLSMode,' - SIPS OFF -',SIPS_Off)

  declare LastMode   { Remembers last state of SLSMode menu }

  declare Leg_Mode   { Legacy Name for SLSMode prior to V150 }

  if Global[G_PFC] = 0     {  If updating from V105 }

    _read_persistent_var(Leg_Mode)  { Recall V105 Legato mode }

    if Leg_Mode = 0  { Initialize to equivalent of prior version }

      SLSMode := SIPS_Off

    else

      SLSMode := Legato_Mode

    end if
  else  { Set 'fresh' install default for SLSMode }
    SLSMode := Legato_Mode

  end if

  _read_persistent_var(SLSMode)   { If updating from self (V150) }

  LastMode := SLSMode { Initialize LastMode same initial SLSMode }   

end function { on_init_SLSMode }

function on_init_Std_PanelMap    { Control Layout for the Standard SLS Panel }

  declare global StdPanel_Map[36] := ( ...

    uPreset,   tXFCap2,       xxx,    tBTmCap,  tBndCap1,    uSetIR, ...

     uXTime,  uAtkFade,  uNodeVol,     uBTime,    uSlope,    tIRBox, ...

        xxx,       xxx,       xxx,        xxx,       xxx,       xxx, ...

    tXFCap1,  uRlsFade,   uOffset,   tBndCap2,     uBend,  tModeCap, ...

    uXtmRng,       xxx,       xxx,    uBTmRng,   uBndRng,  uSLSMode, ...

     uXTmCC,  uRlsMode, uOfstMode,     uBTmCC,    uBndCC,    uLegCC)   

end function { on_init_Std_PanelMap }

function on_init_XTime

  family XTime { XTime parameter family with add-on BtnMenu }

    declare ui_knob Knob (0,MaxXTime,1)  { XTime amount in ms, 0 = Off }

    declare ui_value_edit Range (MinRng,MaxRng,1) { MIDI CC add-on range }

    declare iKnob  { Image of last XTime Knob setting }

    declare Kmax := MaxXTime { Max allowed XTime value }
    declare ui_button Btn    { CC Menu launch button }

    declare CC     { CC#, 0 = unassigned, 128 = PW }    

    declare x      { Current panel location of XTime.Btn }

    declare y

    declare state  { Current state of button (on/off) }

    declare @cap   { Prefix of button caption }           

  end family { XTime }

  set_text(XTime.Knob,' XTime')          { Name the XTime Knob and }  

  set_knob_unit(XTime.Knob,KNOB_UNIT_MS) { Set unit display to ms  }

  XTime.cap := 'XTime CC'           { Menu-Button caption prefix }

  set_text(XTime.Range,'CC Range')  { Name add-on Range Edit control }
       { Legacy Panel Control Names for XTime stuff }
  declare $XTime   { Legacy Name for XTime.Knob prior to V150 }
  declare IXTime   { Legacy Name for XTime.iKnob prior to V150 }
  declare XTmRng   { Legacy Name for XTime.Range prior to V150 }
  declare XTm_CC   { Legacy Name for XTime.CC prior to V150 }
  if Global[G_PFC] < V150  { Updating from version prior to V150 }
    _read_persistent_var($XTime)   { Recall prior panel settings }
    _read_persistent_var(IXTime)
    _read_persistent_var(XTmRng)
    _read_persistent_var(XTm_CC)
    if XTm_CC = -1
      XTm_CC := PitchWheel
    end if
    XTime.Knob := $XTime     { Initialize to prior version parms }
    XTime.iKnob := IXTime
    XTime.Range := XTmRng
    XTime.CC := XTm_CC
  else  { Set 'fresh' install defaults for Panel Parms }
    XTime.Knob := MainParms[uXTime] { Default to Inst_0 setting }

    XTime.iKnob := XTime.Knob       { Default Image to same as Knob }

    XTime.Range := DefRng           { Standard initial range }

    XTime.CC := 0                   { Default to CC unassigned }     
  end if

  _read_persistent_var(XTime.CC)  { If updating from self (V150) }
  SetBtn(XTime)                   { Update assignment-button }

end function { on_init_XTime }

{ ---------------- SLS Version of Common Routines --------------- }
function Fmt105

{ Converts V105 User Presets in PresetParms array to V150 format
  in UserParms array (uses same routine as for V105 -> V110) }

  declare const User_1 := 216  { V105 offset to first User Preset, SLS }

  declare i

  declare j

  declare p105   { Pointer to PresetParms array }

  declare p110   { Pointer to UserParms array }

  

  p105 := User_1 { User Preset #1 starts here in V105 }

  p110 := 0      { User Preset #1 starts here in V110 } 

  for j := 1 to UserPresets  { Do User Presets one by one }

    for i := 0 to 9  { Xfr actual parms used in V105 }

      UserParms[p110 + i] := PresetParms[p105 + i]

    end for  { Now use tokens for parms not available from V105 }

    for i := 10 to MaxParms - 1 

      UserParms[p110 + i] := NoParm 

    end for

    p105 := p105 + 12  { Advance to next preset base }

    p110 := p110 + MaxParms

  end for

end function { Fmt105 }

function Fmt110
{ Converts V110 User Presets to V150 format in UserParms array }
  declare i

  declare j

  declare p0

  

  for j := 0 to UserPresets - 1

    p0 := j*MaxParms

    if UserParms[p0 + uXTmCC] = -1

      UserParms[p0 + uXTmCC] := 128   { Remap Pitch Wheel code }

    end if

    if UserParms[p0 + uBTmCC] = -1

      UserParms[p0 + uBTmCC] := 128   { Remap Pitch Wheel code }

    end if
    if UserParms[p0 + uBndCC] = -1

      UserParms[p0 + uBndCC] := 128  { Remap Pitch Wheel code }

    end if     

  end for  

end function { Fmt110 }



function Load_KeyParms  { Load Parms from PresetBfr }

  LoadParm(XTime.iKnob,uXTime) 

  XTime.Knob := XTime.iKnob

  LoadParm(AtkFade,uAtkFade)

  LoadParm(NodeVol,uNodeVol)

  LoadParm(BTime.iKnob,uBTime)

  BTime.Knob := BTime.iKnob

  LoadParm(Slope,uSlope)

  LoadParm(Bend.iKnob,uBend)

  Bend.Knob := Bend.iKnob

  LoadParm(RlsFade,uRlsFade)

  LoadParm(RlsMode,uRlsMode)

  LoadParm(Offset,uOffset)

  LoadParm(OfstMode,uOfstMode)

end function { Load_KeyParms }



function Load_XParms  { Load Extra Parms from PresetBfr }

  LoadParm(XTime.Range,uXTmRng)

  LoadParm(XTime.CC,uXTmCC)

  LoadParm(BTime.Range,uBTmRng)

  LoadParm(BTime.CC,uBTmCC)

  LoadParm(Bend.Range,uBndRng)

  LoadParm(Bend.CC,uBndCC)

  LoadParm(SLSMode,uSLSMode)

  LoadParm(Leg.CC,uLegCC)

  LoadParm(Global[G_Low_Key],pLowKey)

  LoadParm(Global[G_Top_Key],pTopKey)

  Send_IR  { Broadcast new Inst Range }

  ShowIR   { Update Inst Range Display }

end function { Load_XParms }



function Process_RX

{ Process data-less command or last integer received by RX_Data }

  if ((Preset = Import) and in_range(Global[0],G_PIB_MSC,G_PIB_Tag))

    Do_Import

  end if  { SLS receives no other global data or commands }

end function { Process_RX }



function Recall_Preset(menu_index)

{ Retrieves Preset Parameters from either MainParms or UserParms }

  declare parm0  { Offset to 1st parm of preset }

  declare px     { PresetBfr index }


  if CC_Pending # 0  

    CC_Pending := -2  { Cancel any pending CC assignment }

  end if
  if menu_index < User0

    parm0 := menu_index*KeyParms

    for px := 0 to KeyParms - 1  

      PresetBfr[px] := MainParms[parm0 + px]

    end for  { Get parms for Built-In Preset selected }

  else { menu index indicates a User Preset }

    parm0 := (menu_index - User0)*MaxParms

    for px := 0 to MaxParms - 1

      PresetBfr[px] := UserParms[parm0 + px]

    end for { Get parms for User Preset selected }

  end if

  Load_KeyParms   { Recall Key Parms from buffer }

  if menu_index >= User0 { User Preset being recalled }

    Load_XParms          { Recall extra User parms }

  end if 

  Set_OfstKnob  { Restore correct knob data mode displays }

  Set_RlsKnob
  SetBtn(Bend)  { Restore BtnMenus for CC assignment }
  SetBtn(BTime)
  SetBtn(Leg)
  SetBtn(XTime)

end function { Recall_Preset }



function Save_Preset(upx)

{ Save current panel parameter set in UserParms array at upx }

  declare parm0

  

  parm0 := upx*MaxParms

  UserParms[parm0 + uXTime]    := XTime.Knob

  UserParms[parm0 + uAtkFade]  := AtkFade

  UserParms[parm0 + uNodeVol]  := NodeVol

  UserParms[parm0 + uBTime]    := BTime.Knob

  UserParms[parm0 + uSlope]    := Slope

  UserParms[parm0 + uBend]     := Bend.Knob 

  UserParms[parm0 + uRlsFade]  := RlsFade

  UserParms[parm0 + uRlsMode]  := RlsMode

  UserParms[parm0 + uOffset]   := Offset

  UserParms[parm0 + uOfstMode] := OfstMode

  UserParms[parm0 + uXTmRng]   := XTime.Range

  UserParms[parm0 + uXTmCC]    := XTime.CC

  UserParms[parm0 + uBTmRng]   := BTime.Range

  UserParms[parm0 + uBTmCC]    := BTime.CC

  UserParms[parm0 + uBndRng]   := Bend.Range

  UserParms[parm0 + uBndCC]    := Bend.CC

  UserParms[parm0 + pLowKey]   := Global[G_Low_Key]

  UserParms[parm0 + pTopKey]   := Global[G_Top_Key]

  UserParms[parm0 + uSLSMode]  := SLSMode

  UserParms[parm0 + uLegCC]    := Leg.CC

end function { Save_Preset }

function SetXY(h,x,y)
{ Moves the Control whose assigned 'handle' is h, to position x,y on the panel.
  If x = 0 or y = 0, the Control will be hidden. This case statement ties the
  previously defined index constants to the corresponding control. Negative
  case indices are ignored because they are used by panel/sub-panel maps to
  indicate that no control is anchored in that position. NOTE: SetXY also sets
  the 'internal' x,y values for Button-Menus }
  if h >= 0  { Ignore negative h values }
    select h
      case uPreset                    { Col 1, Std Panel }

        move_control(Preset,x,y)

      case uXTime

        move_control(XTime.Knob,x,y)
      case tXFCap1

        move_control(XFadeCap1,x,y)
      case uXTmRng

        move_control(XTime.Range,x,y)
      case uXTmCC

        move_control(XTime.Btn,x,y)
        XTime.x := x
        XTime.y := y
      case tXFCap2                    { Col 2, Std Panel }

        move_control(XFadeCap2,x,y)        
      case uAtkFade

        move_control(AtkFade,x,y)

      case uRlsFade

        move_control(RlsFade,x,y)

      case uRlsMode

        move_control(RlsMode,x,y)
      case uNodeVol                   { Col 3, Std Panel }

        move_control(NodeVol,x,y)

      case uOffset

        move_control(Offset,x,y)      

      case uOfstMode

        move_control(OfstMode,x,y)        
      case tBTmCap

        move_control(BTimeCap,x,y)    { Col 4, Std Panel }
      case uBTime

        move_control(BTime.Knob,x,y)
      case tBndCap2

        move_control(BendCap2,x,y)        
      case uBTmRng

        move_control(BTime.Range,x,y)
      case uBTmCC

        move_control(BTime.Btn,x,y)
        BTime.x := x
        BTime.y := y        
      case tBndCap1                  { Col 5, Std Panel }

        move_control(BendCap1,x,y)        
      case uSlope

        move_control(Slope,x,y)

      case uBend

        move_control(Bend.Knob,x,y)        
      case uBndRng

        move_control(Bend.Range,x,y)
      case uBndCC

        move_control(Bend.Btn,x,y)
        Bend.x := x
        Bend.y := y        
      case uSetIR                    { Col 6, Std Panel }

        move_control(SetIR,x,y)
      case tIRBox

        move_control(IR_Box,x,y)

      case tModeCap

        move_control(ModeCap,x,y)        
      case uSLSMode

        move_control(SLSMode,x,y)

      case uLegCC

        move_control(Leg.Btn,x,y)
        Leg.x := x
        Leg.y := y
      case tNameDsp                  { Col 1, Rename SubPanel }

        move_control(NameDisplay,x,y)
      case uBackSp

        move_control(BackSpace,x,y)
      case uErase

        move_control(EraseName,x,y)                
      case uAlpha                    { Col 2, Rename SubPanel }

        move_control(Alpha,x,y)

      case uEntChr

        move_control(EnterChar,x,y)  { Col 3, Rename SubPanel }

      case uLoCase

        move_control(LowerCase,x,y)

      case tImpErr                   { ErrPanel }

        move_control(AutoImportError,x,y)

      { end cases }  

    end select
  end if

end function { SetXY }

function Update_Panel

{ Update control panel to reflect assigned CC changes }

  if CC_NUM = Bend.CC     { Update Bend edit box } 

    Update_Knob(Bend)

  end if

  if CC_NUM = BTime.CC    { Update BTime knob }

    Update_Knob(BTime)

  end if

  if CC_NUM = XTime.CC    { Update XTime knob }

    Update_Knob(XTime)

  end if

end function { Update_Panel }